/*
 * Copyright (c) 2019, Beijing Aegean Soft. All rights reserved.
 *
 */

package com.inoteexpress.irpdataexport;

import org.omg.CORBA.OBJECT_NOT_EXIST;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.IOException;
import java.util.*;

/*
 * 整个数据访问，数据逻辑及控制类
 * @author  Sunny
 * @date 2019/03/16
 */

@Service
public class IrpRecordsExporter {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private ExcelExportService exportService;

    // 每次处理的条数（每个Excel文件保存的数量），可以控制系统内存的使用量
    private static int COUNT_PER_REQ = 1000;

    // 用户和机构的map，一次访问，避免多次数据库请求或者连接
    private Map<String, String> communityMap = new HashMap<>(32);
    private Map<String, String> userMap = new HashMap<>(256);

    private void buildCommunityMaps() {
        List<Map<String, Object>> communities = jdbcTemplate.queryForList("select community_id, name from community order by community_id");
        for (Map<String, Object> community : communities) {
            communityMap.put(String.valueOf(community.get("community_id")), (String) community.get("name"));
        }
    }

    private void buildUserMaps() {
        List<Map<String, Object>> users = jdbcTemplate.queryForList("select eperson_id, concat(firstname,' [', email, ']') as name from eperson order by eperson_id;");
        for (Map<String, Object> user : users) {
            userMap.put(String.valueOf(user.get("eperson_id")), (String) user.get("name"));
        }
    }

    private void buildMaps() {
        buildCommunityMaps();
        buildUserMaps();
    }

    // 获取item的总数量，以便确定页数
    private long getRecordCount() {
        Map<String, Object> rec = null;
        if ((rec = jdbcTemplate.queryForMap("select count(*) as CNT from item")) != null) {
            return ((Long) rec.get("CNT")).longValue();
        }
        return 0L;
    }

    // 根据页码，获取items 的 id 列表
    private List<Integer> getItemIds(int pageIndex) {
        List<Map<String, Object>> items = jdbcTemplate.queryForList(String.format("select item_id from item order by item_id offset %d limit %d", pageIndex * COUNT_PER_REQ, COUNT_PER_REQ));
        List<Integer> result = new ArrayList<>(items.size());
        for (Map<String, Object> item : items) {
            result.add((Integer) item.get("item_id"));
        }
        return result;
    }

    // 字段列表，采用TreeSet可以让字段按字母顺序排列
    private static TreeSet<String> fieldMaps = new TreeSet();

    // 将多个元数据结构合并成一条记录Map
    private Map<String, Object> mergeItem(List<Map<String, Object>> fields) {
        Map<String, Object> result = new HashMap<>(32);
        for (Map field : fields) {
            String dc = (String) field.get("dc");
            if (!fieldMaps.contains(dc)) fieldMaps.add(dc);
            String value = (String) field.get("real_value");
            String v = (String) result.get(dc);
            if (v == null) {
                result.put(dc, value);
            } else {
                result.put(dc, v + "; " + value);
            }
        }
        return result;
    }

    // 主函数，导出记录，提供保存的路径
    public void exportRecords(String storePath) throws IOException {
        File outPath = new File(storePath);
        if (!outPath.exists()) { // not found, make it
            outPath.mkdirs();
        }
        if (outPath.isFile()) {
            System.out.println("StorePath must is a directory");
            System.exit(1);
        }
        if (!outPath.exists()) { // double check
            System.out.println("StorePath not found");
            System.exit(1);
        }
        long page = (getRecordCount() - 1) / COUNT_PER_REQ + 1;
        if (page == 0) return;
        long processed = 0;
        buildMaps();
        for (int i = 0; i < page; i++) {
            List<Integer> ids = getItemIds(i);
            List<Map<String, Object>> collections = new ArrayList<>(COUNT_PER_REQ);
            for (Integer id : ids) {
                List<Map<String, Object>> items = jdbcTemplate.queryForList(String.format("select a.*, b.element, b.qualifier from (select * from metadatavalue where item_id = %d) a left join (select * from metadatafieldregistry) b on a.metadata_field_id=b.metadata_field_id", id));
                if (items != null) {
                    for (Map item : items) {
                        String dc = (String) item.get("element");
                        String qualifier = (String) item.get("qualifier");
                        if (qualifier != null)
                            dc = dc + "." + qualifier;
                        item.put("dc", dc);
                        String value = (String) item.get("text_value");
                        if (dc.equals("identifier.user")) {
                            String realName = userMap.get(value);
                            item.put("real_value", realName);
                        } else if (dc.equals("identifier.community")) {
                            String realName = communityMap.get(value);
                            item.put("real_value", realName);
                        } else {
                            item.put("real_value", value);
                        }
                    }
                    collections.add(mergeItem(items));
                }
                processed++;
            }
            exportService.exportXls(collections, fieldMaps.toArray(new String[fieldMaps.size()]), String.format("%s/exports_%d.xls", storePath, i + 1));
        }
        System.out.println(String.format("%d Processed", processed));
    }
}
